package eth

import (
	"fmt"
	"net"
	"os/exec"
	"regexp"
	"runtime"
	"strings"

	"gitee.com/liumou_site/gns/ping"
	"gitee.com/liumou_site/logger"
)

// Gateway 结构体，公开属性
// 表示一个网关信息
type Gateway struct {
	Interface string // 网卡名
	IP        net.IP // 网关IP
}

// GetGateway 公开方法，根据网卡名和IP获取网关信息
func (e *Eth) GetGateway(eth string, ip net.IP) (*Gateway, error) {
	gwIP, err := e.getGatewayIP(eth, ip)
	if err != nil {
		return nil, err
	}
	return &Gateway{
		Interface: eth,
		IP:        gwIP,
	}, nil
}

// getGatewayIP 私有方法，原GetEthGateway逻辑
func (e *Eth) getGatewayIP(eth string, ip net.IP) (net.IP, error) {
	var cmd string
	var out []byte
	var err error
	var gw net.IP
	if len(eth) == 0 {
		return nil, fmt.Errorf("interface name is required")
	}
	switch runtime.GOOS {
	case "windows":
		cmd = fmt.Sprintf("route print -4 | findstr %s", ip.String())
		out, err = exec.Command("cmd", "/c", cmd).Output()
	case "darwin":
		cmd = fmt.Sprintf("netstat -nr | grep %s | awk '{print $2}'", eth)
		out, err = exec.Command("bash", "-c", cmd).Output()
	default:
		cmd = fmt.Sprintf("ip route show dev %s | awk '{print $3}'", eth)
		out, err = exec.Command("bash", "-c", cmd).Output()
	}
	if err != nil {
		logger.Error(err)
		return nil, err
	}
	if strings.EqualFold(runtime.GOOS, "windows") {
		gateway := regexp.MustCompile(`0.0.0.0\s+0.0.0.0\s+(\d+\.\d+\.\d+\.\d+)`).FindStringSubmatch(string(out))
		if len(gateway) > 1 {
			gw = net.ParseIP(gateway[1])
			if gw == nil {
				err = fmt.Errorf("invalid gateway address: %s", gateway[1])
				logger.Error(err)
				fmt.Println(gw)
				return nil, err
			}
			return gw, nil
		}
		logger.Error("未找到网关地址....")
		return nil, fmt.Errorf("invalid gateway address: %s", gateway[1])
	}
	if strings.EqualFold(runtime.GOOS, "darwin") {
		gateway := regexp.MustCompile(`(\d+\.\d+\.\d+\.\d+)`).FindStringSubmatch(string(out))
		if len(gateway) > 1 {
			gw = net.ParseIP(gateway[1])
			if gw == nil {
				return nil, fmt.Errorf("invalid gateway address: %s", gateway[1])
			}
			return gw, nil
		}
		return nil, fmt.Errorf("invalid gateway address: %s", gateway[1])
	}
	gateway, err := e.linuxGetGateway(eth)
	if err != nil {
		logger.Error(err.Error())
		return nil, err
	}
	return gateway, nil
}

// linuxGetGateway 私有方法
func (e *Eth) linuxGetGateway(eth string) (net.IP, error) {
	cmd := fmt.Sprintf("ip route show dev %s | sed -n 1p | awk '{print $3}'", eth)
	out, err := exec.Command("sh", "-c", cmd).Output()
	if err != nil {
		logger.Error("linuxGetGateway: ", err)
		return nil, err
	}
	out = []byte(strings.TrimSpace(string(out)))
	return net.ParseIP(string(out)), nil
}

// GetDefaultInterface 获取当前系统用于连接默认路由的网络接口
// 该方法通过创建一个虚拟的UDP连接（目标为公共DNS服务器），利用系统路由表确定默认出口网卡
// 返回: 成功返回网络接口指针，失败返回错误信息
func (e *Eth) GetDefaultInterface() (*net.Interface, error) {
	// 创建虚拟UDP连接（使用Google公共DNS）
	// 系统会自动选择默认路由的网卡建立连接，通过此连接可反向查询使用的本地地址
	conn, err := net.Dial("udp", "8.8.8.8:53")
	if err != nil {
		return nil, fmt.Errorf("创建探测连接失败: %v", err)
	}
	// 确保连接关闭（延迟执行）
	defer func(conn net.Conn) {
		err = conn.Close()
		if err != nil {
			logger.Error("关闭连接失败: %v", err)
		}
	}(conn)

	// 获取连接使用的本地地址信息（类型断言为UDP地址）
	localAddr := conn.LocalAddr().(*net.UDPAddr)

	// 获取系统所有网络接口列表
	ifNameList, err := net.Interfaces()
	if err != nil {
		logger.Error("获取本地接口失败: %v", err)
		return nil, err
	}
	if len(ifNameList) == 0 {
		return nil, fmt.Errorf("未找到任何网络接口")
	}
	// 遍历所有网络接口，寻找与本地地址匹配的接口
	for _, iface := range ifNameList {
		// 获取接口绑定的所有IP地址
		adders, err := iface.Addrs()
		if err != nil {
			continue // 跳过无法获取地址的接口（可能是权限问题或无效接口）
		}

		// 检查每个地址是否匹配目标IP
		for _, addr := range adders {
			// 类型断言为IPNet，并排除回环地址
			if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
				// 比较接口地址与连接使用的本地地址
				if ipnet.IP.Equal(localAddr.IP) {
					return &iface, nil // 找到匹配的接口
				}
			}
		}
	}

	// 未找到匹配的网卡（可能系统没有默认路由或网络配置异常）
	return nil, fmt.Errorf("未找到默认网卡")
}

// CheckGatewayOnline 检查指定网关IP是否在线，并返回丢包率
// 返回: online(是否在线)、lossRate(丢包率百分比)、err
func (e *Eth) CheckGatewayOnline(gwIP net.IP) (bool, float64, error) {
	if gwIP == nil {
		return false, 100.0, fmt.Errorf("网关IP不能为空")
	}
	p := ping.NewPing(4, 2) // 默认4包，2秒超时
	result, err := p.ICMPWithStats(gwIP.String(), 4, false)
	if err != nil {
		return false, 100.0, err
	}
	// 在线定义为丢包率小于100%
	online := result.LossRate < 100.0
	return online, result.LossRate, nil
}
